package com.zhdl.modules.wallpulley.web.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.common.util.DelayUtil;
import com.zhdl.common.util.WebResult;
import com.zhdl.common.ytools.HttpClientUtil;
import com.zhdl.hardware.motor.leisai.service.LSCmdSendService;
import com.zhdl.hardware.plc.siemens.service.SiemensCmdSendService;
import com.zhdl.modules.common.entity.ProcessRecords;
import com.zhdl.modules.common.entity.ProcessWarnMessage;
import com.zhdl.modules.common.service.ProcessRecordsService;
import com.zhdl.modules.common.service.ProcessWarnService;
import com.zhdl.modules.common.web.resp.WarnMemDevice;
import com.zhdl.modules.wallpulley.entity.ParameterSettings;
import com.zhdl.modules.wallpulley.web.WallPulleyProcess;
import com.zhdl.modules.wallpulley.web.req.CalibrationResult;
import com.zhdl.modules.wallpulley.web.req.EventRecordsReq;
import com.zhdl.modules.wallpulley.web.resp.*;
import com.zhdl.modules.wallpulley.web.service.WallPulleyService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.HttpPost;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping(path = "/wallPulley", produces = MediaType.APPLICATION_JSON_VALUE)
public class WallPulleyController {

    private static final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    public static int count;
    public static int okResult;
    public static int failResult;
    private final Map<Integer, SseEmitter> sseEmitters = new ConcurrentHashMap<>();
    String port = "2", slaveId = "01";
    @Resource
    private LSCmdSendService lsCmdSendService;
    @Resource
    private WallPulleyProcess wallPulleyProcess;
    @Resource
    private WallPulleyService wallPulleyService;
    private long sseSeq;

//    @Resource
//    private SiemensReceiveHandelDaoImpl siemensReceiveHandelDao;
//
//    String plcValue0 , plcValue1;
//    @GetMapping("plcGetValue")
//    public WebResult<String> plcGetValue(String slaveId,String address, int count){
//        final boolean[] open = {true};
//        while (open[0]){
//            siemensReceiveHandelDao.raedValueByAddress(slaveId, address, count, s -> {
//                log.info("完整完整"+s);
//                plcValue0 = s;
//            });
//            if (!plcValue0.isEmpty()){
//                open[0] = true;
//                return WebResult.okResult(plcValue0);
//
//            }
//        }
//        return WebResult.okResult(plcValue0);
//    }
//
//    @GetMapping("plcWriteValue")
//    public WebResult<String> plcWriteValue(String slaveId,String address, int value, int count){
//        siemensReceiveHandelDao.writeValueByAddress(slaveId,address, IntToHexUtil.shortToHex(value));
//        siemensReceiveHandelDao.raedValueByAddress(slaveId, address, count, s -> {
//            plcValue1 = s;
//            log.info("完整完整"+s);
//        });
//        return WebResult.okResult(plcValue1);
//    }

//    @GetMapping("/test")
//    public void test(int ad1,int ad2,int ad3){
//        wallPulleyProcess.ad1 = ad1;
//        wallPulleyProcess.ad2 = ad2;
//        wallPulleyProcess.ad3 = ad3;
//    }
//    @GetMapping("/test1")
//    public void test1(boolean status){
//        wallPulleyProcess.testStatus = status;
//    }

    @GetMapping("/OrderNumberInput")
    public WebResult<String> OrderNumberInput(
            String WorkOrderNumber,String PowerStationName, String IntervalNumber
    ) {
        log.info("工单编号:{},电站名称:{},间隔号:{}", WorkOrderNumber, PowerStationName, IntervalNumber);
        wallPulleyProcess.workOrderNumber = WorkOrderNumber;
        wallPulleyProcess.powerStationName = PowerStationName;
        wallPulleyProcess.intervalNumber = IntervalNumber;
        return WebResult.okResult("工单编号:"+ WorkOrderNumber + "电站名称:"+ PowerStationName +",间隔号:" + IntervalNumber);
    }

    @GetMapping("/OrderNumberGenerate")
    public WebResult<String> OrderNumberGenerate() {
        String WorkOrderNumber = UUID.randomUUID().toString();
        String PowerStationName = UUID.randomUUID().toString();
        String IntervalNumber = UUID.randomUUID().toString();
        log.info("工单编号:{},电站名称:{},间隔号:{}", WorkOrderNumber, PowerStationName, IntervalNumber);
        wallPulleyProcess.workOrderNumber = WorkOrderNumber;
        wallPulleyProcess.powerStationName = PowerStationName;
        wallPulleyProcess.intervalNumber = IntervalNumber;
        return WebResult.okResult("工单编号:"+ WorkOrderNumber + "电站名称:"+ PowerStationName +",间隔号:" + IntervalNumber);
    }


    /**
     * 接收 Mes工单号-电站名称-间隔号
     *
     * @param WorkOrderNumber 工单编号
     * @param PowerStationName 电站名称
     * @param IntervalNumber 间隔号
     * @return 设置的工单号
     */
    @PostMapping("/setMesParam")
    public WebResult<String> setMesParam(
            @RequestParam String WorkOrderNumber,@RequestParam String PowerStationName, @RequestParam String IntervalNumber
    ) {
        log.info("工单编号:{},电站名称:{},间隔号:{}", WorkOrderNumber, PowerStationName, IntervalNumber);
        wallPulleyProcess.workOrderNumber = WorkOrderNumber;
        wallPulleyProcess.powerStationName = PowerStationName;
        wallPulleyProcess.intervalNumber = IntervalNumber;
        return WebResult.okResult("工单编号:"+ WorkOrderNumber + "电站名称:"+ PowerStationName +",间隔号:" + IntervalNumber);
    }

    /**
     * 电机流程开始
     *
     * @param id 型号ID
     */
    @GetMapping("/motorProcess")
    public WebResult<String> motorProcess(int id) {
        if (!wallPulleyProcess.workOrderNumber.isEmpty()) {
            if (!wallPulleyProcess.isRunning) {
                if (id == 0) {
                    wallPulleyProcess.WallPulleyProcessStart(0);
                    log.info("进入型号xxx0");
                } else if (id == 1) {
                    wallPulleyProcess.WallPulleyProcessStart(1);
                    log.info("进入型号xxx1");
                }
            }else{
                return WebResult.okResult("Motor model is:" + id + ", already start process success!");
            }
        }
        return WebResult.okResult("Motor model is:" + id + ", already start process success!");
    }
    /**
     * 手动控制电机
     */
    @GetMapping("/motorManual")
    public WebResult<String> motorManual(int distance, int speed) {
//        distance = (((distance / 10000) * 5) / 7);
        distance = ((distance * 7) / 5 ) * 10000;
        lsCmdSendService.leisaiSetMoveSpeed(port, slaveId, speed);
        lsCmdSendService.leisaiSetMoveDist(port, slaveId, distance);
        return WebResult.okResult("Motor port is:" + port + ",slaveId is " + slaveId + ", already run success!");
    }

    @GetMapping("/motorJogRun")
    public WebResult<String> motorJogRun(int model,int speed,boolean run) {
        if (run){
            lsCmdSendService.leisaiSetMotorModel("2","01",3);
            // model 0 下 1 上`
            if (model == 0){
                // 暂时固定电机的运行速度
                DelayUtil.delayedExecution(100, () -> {
                    lsCmdSendService.leisaiSetMoveSpeed(port,slaveId,100);
                    log.info("电机向下运动");
                });
            } else {
                // 暂时固定电机的运行速度
                DelayUtil.delayedExecution(100, () -> {
                    lsCmdSendService.leisaiSetMoveSpeed(port, slaveId, -100);
                    log.info("电机向上运动");
                });
            }
            DelayUtil.delayedExecution(200, () -> {
                lsCmdSendService.leisaiReady(port,slaveId);
                log.info("电机运动");
            });
        } else {
            DelayUtil.delayedExecution(200, () -> {
                lsCmdSendService.leisaiEmergencyStop(port,slaveId);
                log.info("电机停止运动");
            });
        }

        return WebResult.okResult("Motor port is:" + port + ",slaveId is " + slaveId + ", already run success!");
    }

    /**
     * 测试
     */
    @GetMapping("/motorResetting")
    public WebResult<String> motorResetting() {
        wallPulleyProcess.isRunning = false;
        return WebResult.okResult("process status already reset");
    }

    /**
     * 修改参数
     */
    @PostMapping("/paramSetting")
    public WebResult<String> paramSetting(@RequestBody ParameterSettingsResp resp) {
        int modelDistance = resp.getModelDistance();
        int modelEmpty = resp.getModelEmpty();
        int modelZero = resp.getModelZero();
        resp.setModelDistance(((modelDistance * 7) / 5) * 10000);
        resp.setModelEmpty(((modelEmpty * 7) / 5) * 10000);
        resp.setModelZero(((modelZero * 7) / 5) * 10000);
        wallPulleyService.saveParamSetting(resp);
        String jsonStr = JSONUtil.toJsonStr(resp);
        return WebResult.okResult(jsonStr);
    }

    /**
     * 查数据库_字典型号
     */
    @GetMapping("/findAllParam")
    public WebResult<String> findAllParam() {
        List<ParameterSettingsResp> allParam = wallPulleyService.findAllParam();
        for (ParameterSettingsResp parameterSettingsResp : allParam) {
            int modelDistance = parameterSettingsResp.getModelDistance();
            int modelEmpty = parameterSettingsResp.getModelEmpty();
            parameterSettingsResp.setModelDistance((((modelDistance / 10000) * 5) / 7));
            parameterSettingsResp.setModelEmpty((((modelEmpty / 10000) * 5) / 7));
        }
        String jsonStr = JSONUtil.toJsonStr(allParam);
        return WebResult.okResult(jsonStr);
    }

    /**
     * 查数据库_事件所有内容
     */
    @PostMapping("/findAllEvent")
    public WebResult<EventListResp> findAllEvent(@RequestParam int pageNumber, @RequestParam int pageSize) {
        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        EventListResp eventListResp = new EventListResp();
        Page<EventRecordsResp> allEvents = wallPulleyService.findAllEvents(pageable);
        eventListResp.setList(allEvents);
        eventListResp.setCount(count);
        eventListResp.setOkResult(okResult);
        eventListResp.setFailResult(failResult);
        String jsonStr = JSONUtil.toJsonStr(eventListResp);
        log.info(jsonStr);
        return WebResult.okResult(eventListResp);
    }

    @GetMapping("/calibrationRun")
    public WebResult<String> calibrationRun() {
        if (wallPulleyProcess.calibrationIsRun){
            return WebResult.okResult("fail");
        }
        wallPulleyProcess.calibrationIsRun = true;
        lsCmdSendService.leisaiSetMoveSpeed("2", "01", 400);
        wallPulleyProcess.motorCalibration();
        return WebResult.okResult("ok");
    }

    @GetMapping("/calibrationGet")
    public WebResult<CalibrationResult> calibrationGet() {
        CalibrationResult calibrationResult = new CalibrationResult();
        boolean calibrationIsRun = wallPulleyProcess.calibrationIsRun;
        boolean calibrationIsOk = wallPulleyProcess.calibrationIsOk;
        calibrationResult.setRunStatus(calibrationIsRun);
        calibrationResult.setRunOkStatus(calibrationIsOk);
        if (calibrationIsRun) {
            calibrationResult.setCalibrationResult(0.0);
        }
        if (calibrationIsOk) {
            double calibrationPlcValue = wallPulleyProcess.calibrationPlcValue / 1000.00;
            calibrationResult.setCalibrationResult(calibrationPlcValue);
        }
        return WebResult.okResult(calibrationResult);
    }


    @PostMapping("/findAllRecords")
    public WebResult<EventListResp> findAllRecords(@RequestBody @Validated EventRecordsReq request, @RequestParam int pageNumber, @RequestParam int pageSize) {
        //分页
        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        EventListResp eventListResp = new EventListResp();
        if (request.getStartTime().isEmpty() && request.getEndTime().isEmpty()) {
            wallPulleyService.getEventCount(eventListResp);
            Page<EventRecordsResp> allEvents = wallPulleyService.findAllEvents(pageable);
            eventListResp.setList(allEvents);
            String jsonStr = JSONUtil.toJsonStr(eventListResp);
            log.info(jsonStr);
        } else {
            Page<EventRecordsResp> allPage = wallPulleyService.findAllRecords(request, pageable);
            eventListResp.setList(allPage);
            eventListResp.setCount(count);
            eventListResp.setOkResult(okResult);
            eventListResp.setFailResult(failResult);
            String jsonStr = JSONUtil.toJsonStr(eventListResp);
            log.info(jsonStr);
        }
        return WebResult.okResult(eventListResp);
    }

    /**
     * 查数据库_事件通过事件Id查询
     */
    @GetMapping("/findEventById")
    public WebResult<String> findEventById(int id) {
        EventInfoSSeResp infoByEventId = wallPulleyService.findInfoByEventId(id);
        String jsonStr = JSONUtil.toJsonStr(infoByEventId);
        return WebResult.okResult(jsonStr);
    }

    @GetMapping("/findSSeDate")
    public WebResult<TensileDistanceSseResp> findSSeDate(){
        wallPulleyProcess.tdRespSse.setDatePointResps(wallPulleyProcess.datePointResps);
        return WebResult.okResult(wallPulleyProcess.tdRespSse);
    }

    @GetMapping("/findSSeDataResult")
    public WebResult<TDRunResultResp> findSSeDataResult(){
        return WebResult.okResult(wallPulleyProcess.tdRunResultResp);
    }

    @GetMapping("/findSSeDataList")
    public WebResult<List<TensileDistanceSseResp>> findSSeDataList(){
        List<TensileDistanceResp> memoryCompare = new ArrayList<>();
        memoryCompare.addAll(wallPulleyProcess.memoryCompare);
        List<TensileDistanceSseResp> memoryCompare1 = new ArrayList<>();
        for (TensileDistanceResp tensileDistanceResp : memoryCompare) {
            TensileDistanceSseResp tensileDistanceSseResp = new TensileDistanceSseResp();
            BeanUtils.copyProperties(tensileDistanceResp, tensileDistanceSseResp);
            tensileDistanceSseResp.setDistanceValue(tensileDistanceResp.getDistanceValue()/10000.00 * 5 / 7);
            tensileDistanceSseResp.setTensileValue(tensileDistanceResp.getTensileValue()/1000.00);
            memoryCompare1.add(tensileDistanceSseResp);
        }
        return WebResult.okResult(memoryCompare1);
    }


    @GetMapping("/findSSeDataList1")
    public WebResult<List<TensileDistanceResp>> findSSeDataList1(){
        List<TensileDistanceResp> memoryCompare = wallPulleyProcess.memoryCompare;
        return WebResult.okResult(memoryCompare);
    }


    /**
     * 通过型号Id和时间进行查询
     */
    @GetMapping("/findEventByTime")
    public WebResult<String> findEventByTime(int id) {
        EventInfoSSeResp infoByEventId = wallPulleyService.findInfoByEventId(id);
        String jsonStr = JSONUtil.toJsonStr(infoByEventId);
        return WebResult.okResult(jsonStr);
    }

    /**
     * 首页数据请求
     */
    @GetMapping(value = "/sse/{id}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter handleSse(@PathVariable Integer id) {
        log.info(id.toString());
        SseEmitter emitter = new SseEmitter(36000000L);
//        SseEmitter emitter = new SseEmitter(10000L);
        sseEmitters.put(id, emitter);
        // 超时移除
        emitter.onTimeout(() -> {
            emitter.complete();
            sseEmitters.remove(id);
        });
        // 完成移除
        emitter.onCompletion(() -> sseEmitters.remove(id));
        // 每一秒发送一条消息
        executorService.scheduleAtFixedRate(() -> {
            ObjectMapper mapper = new ObjectMapper();
            wallPulleyProcess.tdRespSse.setDatePointResps(wallPulleyProcess.datePointResps);
            //加载内存数据
            WebResult<TensileDistanceSseResp> sseResp = WebResult.okResult(wallPulleyProcess.tdRespSse);
            try {
                emitter.send(SseEmitter.event().id(String.valueOf(getSseSeq())).data(mapper.writeValueAsString(sseResp), MediaType.APPLICATION_JSON));
                log.info("send" + sseResp);
            } catch (IOException e) {
                emitter.complete();
            }
        }, 0, 1, TimeUnit.SECONDS);

        return emitter;
    }

    /**
     * 获取SSE序号
     */
    private long getSseSeq() {
        if (sseSeq > 65535L * 65535) sseSeq = 0;
        return sseSeq++;
    }

    @Resource
    private ProcessRecordsService processRecordsService;

    @GetMapping("/selfCheck")
    public WebResult<String> selfChecking(boolean isSelfCheck) {
        ProcessRecords byId = processRecordsService.findById(1);
        byId.setSelfChecking(isSelfCheck);
        processRecordsService.saveProcessDao(byId);
        return WebResult.okResult("开机自检功能-" + (isSelfCheck ? "开启":"关闭") + "-成功!!!");
    }

    @Resource
    private SiemensCmdSendService siemensReceiveHandelDao;

    @GetMapping("/nowWarnRest")
    public WebResult<String> leisaiNowWarnReset(int id) {
       lsCmdSendService.leisaiNowWarnReset("2","01");
       siemensReceiveHandelDao.siemensWriteValue("0000","1","0000","0200");
       return WebResult.okResult("报警复位完成");
    }

    @GetMapping("/lastWarnRest")
    public WebResult<String> leisaiLastWarnReset(int id) {
        lsCmdSendService.leisaiLastWarnReset("2","01");
        siemensReceiveHandelDao.siemensWriteValue("0000","1","0000","0200");
        return WebResult.okResult("报警复位完成");
    }


    @GetMapping("/homeInfo")
    public List<TensileDistanceResp> HomeInfo() {
        return wallPulleyProcess.memoryCompare;
    }

    /**
     * 雷赛电机 回零
     */
    @GetMapping("/lsMotorBack")
    public WebResult<String> lsMotorBack(int id) {
        /* 设置电机运行和模式 */
        lsCmdSendService.leisaiSetMotorModel("2", "01", 1);
        ParameterSettings parameterById = wallPulleyProcess.tensileDistanceService.findParameterById(id);
        int modelZero = parameterById.getModelZero();
        lsCmdSendService.leisaiSetMoveDist("2", "01", modelZero);
        DelayUtil.delayedExecution(1000, () -> wallPulleyProcess.releaseBackOrigin());
        return WebResult.okResult("Motor port is:" + "2" + ",slaveId is " + "01" + ", already back origin success!");
    }
    /**
     * 雷赛电机 急停
     */
    @GetMapping("/lsMotorEmergencyStop")
    public WebResult<String> lsMotorEmergencyStop() {
        wallPulleyProcess.siemensReceiveHandelDao.siemensWriteValue("0000","1","0000","0000");
        lsCmdSendService.leisaiEmergencyStop("2", "02");
        wallPulleyProcess.release();
        return WebResult.okResult("Motor port is:" + "2" + ",slaveId is " + "01" + ", already Emergency Stop success!");
    }

    @Resource
    ProcessWarnService processWarnService;

    /**
     * 查数据库_事件所有内容
     */
    @PostMapping("/faultInfo")
    public WebResult<WarnMemDevice> faultInfo(@RequestParam int pageNumber, @RequestParam int pageSize) {
        Pageable pageable = PageRequest.of(pageNumber, pageSize);
        WarnMemDevice memDevice = new WarnMemDevice();
        Page<ProcessWarnMessage> allByPage = processWarnService.findAllByPage(pageable);
        memDevice.setList(allByPage);
        return WebResult.okResult(memDevice);
    }
}
